package com.myidis.servlet;

import java.util.ArrayList;
import java.util.List;

import org.rosuda.REngine.REXP;
import org.rosuda.REngine.Rserve.RConnection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.auxiliary.Line;
import com.auxiliary.NeuralNetwork;
import com.auxiliary.QuotaDataFinder;
import com.auxiliary.SeasonAdjuster;
import com.auxiliary.TimeSequence;
import com.myidis.entity.CIResult;
import com.myidis.mapper.QuotaMapper;
import com.myidis.request.BBReq;
import com.myidis.request.DICalculatorReq;
import com.myidis.request.ForecastReq;
import com.myidis.request.SeasonAdjustReq;
import com.myidis.response.ForecastCompareRes;
import com.myidis.response.ForecastRes;

@Service
public class ForecastServlet {
	
	@Autowired
	private QuotaMapper quotaMapper;
	@Autowired
	private AnalysisServlet anaServlet;
	@Autowired
    private CICalculateServlet cICalculateServlet;
	
	/*
	@Autowired
    SignalIndexCalculatorServlet signalIndexCalculatorServlet;
    */
	
	public ForecastRes forecast(ForecastReq req) {
		//若指标数组为空或没有数据，返回null
		if(req.getAnalysisQuota() == null || req.getAnalysisQuota().length <= 0)
			return null;
		
		//建立时间序列类TimeSequence集合，并进行数据完整性检查，不需要进行季节调整
		List<TimeSequence> sequenceList = anaServlet.checkListIntegrality(req, req.isSeasonAdjust());
		
		int count = req.getFrequency() == 1? 12: 4;
		
		ForecastRes res = new ForecastRes();
		for(TimeSequence sequence: sequenceList) {
			
			//设置返回数据
			String name = quotaMapper.getOne(sequence.getQuota()).getChineseName();
			
			Line line = new Line(name, ARIMA(sequence.getValueList(), sequence.getDateList().get(0), req.getForecastCount()));
			
			res.getLineList().add(line);
			res.getLineNames().add(name);
			res.setxAxis(sequence.getDateList());
		}
		return res;
	}
	
	
	public ForecastRes CI(ForecastReq req) {
		
		List<CIResult> ciRes = cICalculateServlet.calculate(req.getDIReq());
		
		//预测数据数
		int count = req.getForecastCount();
		
		ForecastRes res = new ForecastRes();
		for(CIResult ci: ciRes) {
			
			//设置返回数据
			String name = ci.getSubject();
			
			//预测曲线计算
			Line line = new Line(name, ARIMA(ci.getBenchmarks(), ci.getDates().get(0), count));
			
			res.getLineList().add(line);
			res.getLineNames().add(name);
			res.setxAxis(ci.getDates());
		}
		
		return res;
	}
	
	public ForecastRes SL(ForecastReq req) {
		
		List<CIResult> ciRes = cICalculateServlet.calculate(req.getDIReq());
		
		//预测数据数
		int count = req.getForecastCount();
		
		ForecastRes res = new ForecastRes();
		for(CIResult ci: ciRes) {
			
			//设置返回数据
			String name = ci.getSubject();
			
			//预测曲线计算
			Line line = new Line(name, ARIMA(ci.getBenchmarks(), ci.getDates().get(0), req.getForecastCount()));
			
			res.getLineList().add(line);
			res.getLineNames().add(name);
			res.setxAxis(ci.getDates());
		}

		return res;
	}
	
	//ARIME预测
	private List<Double> ARIMA(List<Double> data, String start, int count) {

		List<Double> forcList = new ArrayList<Double>();
		
		try{
			//建立R连接
			RConnection rc = new RConnection();
			String fileName = "E:\\arima.R";
			rc.assign("fileName", fileName);
			rc.eval("source(fileName)");
			
			//建立数据数组
			double[] datas = new double[data.size()];
			for(int i = 0; i < data.size(); i++)
				datas[i] = data.get(i);
			rc.assign("data", datas);
			
			//分隔时间
			String[] time = start.split("-");
		
			//进行ARIMA预测
			REXP rexp = rc.eval("ARIMAForc(data, " + 12 + ", " + time[0] + ", " + time[1] + ", " + count + ")");
			
			//获取结果
			double[][] asd = rexp.asDoubleMatrix();
			
			//结果有理化
			for(double[] v: asd)
				forcList.add(Double.isNaN(v[0])? v[1]: v[0]);
			
			rc.close();
		}
		catch(Exception e) {
			e.printStackTrace();
		}
		
		return forcList;
	}
	
	public ForecastCompareRes compare(SeasonAdjustReq req) {
		
		ForecastCompareRes res = new ForecastCompareRes();
		
		//若指标id为0，说明数据错误，返回null
		if(req.getQuota() == 0)
			return null;
		
		//进行数据完整性检查
		TimeSequence sequence = anaServlet.checkIntegrality(new QuotaDataFinder(req.getQuota(), req));
		//若不通过返回null
		if(sequence == null)
			return null;
		
		int count = req.getFrequency() == 1? 12: 4;

		//进行季节调整
		SeasonAdjuster adjust = new SeasonAdjuster(sequence, req.getFrequency(), 1);
		
		List<Double> xlist = adjust.getTCList();//adjust.getTCList();
		
		NeuralNetwork network = new NeuralNetwork(xlist, 12, 1);
		
		res.setxList(network.normalizeList);
		
		List<Double> forecast = network.compare(12);
		
		res.setForecastList(forecast);

		
		return res;
	}
}
